import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
import axios from 'axios'
import { AxiosLoading } from './loading'
import { STORAGE_AUTHORIZE_KEY, useAuthorization } from '@/composables/authorization'
import { ContentTypeEnum, RequestEnum } from '@/enums/http-enum'
import router from '@/router'

export interface ResponseBody<T = any> {
  code: number
  data?: T
  msg: string
}

export interface RequestConfigExtra {
  token?: boolean
  customDev?: boolean
  loading?: boolean
}
const instance: AxiosInstance = axios.create({
  // 默认走统一的前缀（生产/测试环境通过反向代理或网关）
  baseURL: import.meta.env.VITE_APP_BASE_API ?? '/',
  timeout: 60000,
  headers: { 'Content-Type': ContentTypeEnum.JSON },
})

// 测试日志 - 这个应该在模块加载时立即执行
console.log('🚀 REQUEST.TS 模块已加载！', new Date().toLocaleTimeString())
const axiosLoading = new AxiosLoading()
async function requestHandler(config: InternalAxiosRequestConfig & RequestConfigExtra): Promise<InternalAxiosRequestConfig> {
  // 测试日志 - 请求拦截器被调用
  console.log('🔥 请求拦截器被调用！', config.url, new Date().toLocaleTimeString())
  
  // 处理请求前的url
  // 开发环境统一直连后端（已禁用本地 mock），无需在每个接口上设置 customDev
  if (import.meta.env.DEV && import.meta.env.VITE_APP_BASE_URL_DEV) {
    config.baseURL = import.meta.env.VITE_APP_BASE_URL_DEV
    // 直连后端时携带跨域 Cookie（后端基于 Cookie 鉴权）
    config.withCredentials = true
  }
  const token = useAuthorization()

  console.log(token.value)

  if (token.value && config.token !== false)
    config.headers.set(STORAGE_AUTHORIZE_KEY, token.value)
  // 移除多语言头注入，统一由后端按需处理
  if (config.loading)
    axiosLoading.addLoading()
  // 统一打印请求日志，帮助定位是否真正发起请求
  try {
    const method = (config.method || '').toUpperCase()
    const base = config.baseURL || ''
    const url = config.url || ''
    console.log(`[REQ] ${method} ${base}${url}`, { token: !!token.value })
  } catch (_) {}
  return config
}

// 响应拦截器
function responseHandler(response: AxiosResponse<ResponseBody<any>>): ResponseBody<any> {
  console.log("响应拦截器被调用！", response)
  // 统一处理正常响应与业务码
  if (response.status === 200) {
    console.log("响应成功")
    const body = response.data
    // 如果后端以 200 返回并且 data 是一个跳转地址（字符串），也按 data 进行重定向
    const targetFromBody = (body as any)?.data
    if (typeof targetFromBody === 'string' && targetFromBody.trim().length > 0) {
      const token = useAuthorization()
      const axiosLoading = new AxiosLoading()
      const normalized = targetFromBody
        .trim()
        .replace('/#/home/login', '/login')
        .replace('#/home/login', '/login')
      // 如果是跳到登录页，清除本地会话
      if (normalized.includes('/login'))
        token.value = null
      // 关闭全局 loading，避免遮罩停留
      axiosLoading.closeLoading()
      if (/^https?:\/\//.test(normalized))
        window.location.href = normalized
      else router.replace(normalized as string).catch(err => err)
      // 阻断后续处理
      throw new Error('Redirect')
    }
    if (body?.code === 90010050027) {
      // 会话失效，跳登录
      const token = useAuthorization()
      token.value = null
      router.replace('/login').catch(err => err)
      // 阻断后续处理
      throw new Error('Unauthorized')
    }
    return body
  }
  if (response.status === 302) {
    console.log("当前被重定向了")
    const target = (response.data as any)?.data as string
    const normalized = typeof target === 'string' ? target.replace('/#/home/login', '/login').replace('#/home/login', '/login') : target
    // 如果是跳到登录页，清除本地会话
    if (typeof normalized === 'string' && normalized.includes('/login')) {
      const token = useAuthorization()
      token.value = null
    }
    // 302 重定向前关闭全局 loading，避免遮罩停留
    axiosLoading.closeLoading()
    if (typeof normalized === 'string' && /^https?:\/\//.test(normalized)) {
      window.location.href = normalized
    }
    else {
      router.replace(normalized as string).catch(err => err)
    }
    // 阻断后续处理
    throw new Error('Redirect')
  }
  // 其他状态统一跳 403
  router.replace('/403').catch(err => err)
  throw new Error('Forbidden')
}

function errorHandler(error: AxiosError): Promise<any> {
  const token = useAuthorization()
  const notification = useNotification()

  if (error.response) {
    const { data, status, statusText } = error.response as AxiosResponse<ResponseBody>
    if (status === 401) {
      notification?.error({
        message: '401',
        description: data?.msg || statusText,
        duration: 3,
      })
      /**
       * 这里处理清空用户信息和token的逻辑，后续扩展
       */
      token.value = null
      router
        .push({
          path: '/login',
          query: {
            redirect: router.currentRoute.value.fullPath,
          },
        })
        .then(() => {})
    }else if (status === 403) {
      notification?.error({
        message: '403',
        description: data?.msg || statusText,
        duration: 3,
      })
    }else if (status === 500) {
      notification?.error({
        message: '500',
        description: data?.msg || statusText,
        duration: 3,
      })
    }else {
      notification?.error({
        message: '服务错误',
        description: data?.msg || statusText,
        duration: 3,
      })
    }
  }
  else {
    // 无响应，多为网络异常或超时
    const msg = (error as any)?.message || '网络异常或请求超时'
    notification?.error({
      message: '网络异常',
      description: msg,
      duration: 3,
    })
  }
  return Promise.reject(error)
}
interface AxiosOptions<T> {
  url: string
  params?: T
  data?: T
}
instance.interceptors.request.use(requestHandler)

instance.interceptors.response.use(responseHandler, errorHandler)

export default instance
function instancePromise<R = any, T = any>(options: AxiosOptions<T> & RequestConfigExtra): Promise<ResponseBody<R>> {
  const { loading } = options
  return new Promise((resolve, reject) => {
    instance.request(options).then((res) => {
      resolve(res as any)
    }).catch((e: Error | AxiosError) => {
      reject(e)
    })
      .finally(() => {
        if (loading)
          axiosLoading.closeLoading()
      })
  })
}
export function useGet< R = any, T = any>(url: string, params?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {
  const options = {
    url,
    params,
    method: RequestEnum.GET,
    ...config,
  }
  return instancePromise< R, T >(options)
}

export function usePost< R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {
  const options = {
    url,
    data,
    method: RequestEnum.POST,
    ...config,
  }
  return instancePromise< R, T >(options)
}

export function usePut< R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {
  const options = {
    url,
    data,
    method: RequestEnum.PUT,
    ...config,
  }
  return instancePromise<R, T>(options)
}

export function useDelete< R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {
  const options = {
    url,
    data,
    method: RequestEnum.DELETE,
    ...config,
  }
  return instancePromise<R, T>(options)
}
